package mmpathgen.callgraphanalysis;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.List;

import org.junit.Test;

import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.jimple.toolkits.callgraph.CHATransformer;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.Edge;
import soot.options.Options;

public class CallGraphVisitorTest {

	@Test
	public void testVisitNodesByWFS() {
		Options.v().set_whole_program(true);
		Options.v().set_keep_line_number(true);
		// Options.v().setPhaseOption("cg", "verbose:true");
		Options.v().setPhaseOption("cg", "safe-forname:true");
		Options.v().setPhaseOption("cg", "safe-newinstance:true");

		String packageName = "wei.he.stkm";
		String className = "Main";
		// SootClass mainClass = Scene.v().loadClassAndSupport(
		// "testers.CallGraphs");
		SootClass mainClass = Scene.v().loadClassAndSupport(
				packageName + "." + className);
		mainClass.setApplicationClass();
		Scene.v().setMainClass(mainClass);

		// SootClass a = Scene.v().loadClassAndSupport("testers.A");
		SootClass a = Scene.v().loadClassAndSupport("wei.he.stkm.Bike");
		SootClass b = Scene.v().loadClassAndSupport("wei.he.stkm.BikeShop");
		SootClass c = Scene.v().loadClassAndSupport("wei.he.stkm.Fiero");
		SootClass d = Scene.v().loadClassAndSupport("wei.he.stkm.Pulsar");
		SootClass e = Scene.v().loadClassAndSupport("wei.he.stkm.Splendor");
		a.setApplicationClass();
		b.setApplicationClass();
		c.setApplicationClass();
		d.setApplicationClass();
		e.setApplicationClass();

		CHATransformer.v().transform();

		CallGraph cg = Scene.v().getCallGraph();
		UnfilteredCallGraph ucg = CallGraphAnalysis.getUnfilteredCallGraph(cg);
		List<SootMethod> mtdList = CallGraphVisitor.visitNodesInTopologicalOrder(ucg);
		for (SootMethod mtd : mtdList) {
			System.out.println(mtd);
		}

		assertTrue(mtdList.size() != 0);
		// fail("Not yet implemented");
	}

	@Test
	public void testVisitNodesByWFSInReverseOrder() {
		Options.v().set_whole_program(true);
		Options.v().set_keep_line_number(true);
		// Options.v().setPhaseOption("cg", "verbose:true");
		Options.v().setPhaseOption("cg", "safe-forname:true");
		Options.v().setPhaseOption("cg", "safe-newinstance:true");

		String packageName = "wei.he.stkm";
		String className = "Main";
		// SootClass mainClass = Scene.v().loadClassAndSupport(
		// "testers.CallGraphs");
		SootClass mainClass = Scene.v().loadClassAndSupport(
				packageName + "." + className);
		mainClass.setApplicationClass();
		Scene.v().setMainClass(mainClass);

		// SootClass a = Scene.v().loadClassAndSupport("testers.A");
		SootClass a = Scene.v().loadClassAndSupport("wei.he.stkm.Bike");
		SootClass b = Scene.v().loadClassAndSupport("wei.he.stkm.BikeShop");
		SootClass c = Scene.v().loadClassAndSupport("wei.he.stkm.Fiero");
		SootClass d = Scene.v().loadClassAndSupport("wei.he.stkm.Pulsar");
		SootClass e = Scene.v().loadClassAndSupport("wei.he.stkm.Splendor");
		a.setApplicationClass();
		b.setApplicationClass();
		c.setApplicationClass();
		d.setApplicationClass();
		e.setApplicationClass();

		CHATransformer.v().transform();

		CallGraph cg = Scene.v().getCallGraph();
		UnfilteredCallGraph ucg = CallGraphAnalysis.getUnfilteredCallGraph(cg);
		List<SootMethod> mtdList = CallGraphVisitor
				.visitNodesInReverseTopologicalOrder(ucg);
		for (SootMethod mtd : mtdList) {
			System.out.println(mtd);
		}

		assertTrue(mtdList.size() != 0);
		// fail("Not yet implemented");
	}

	@Test
	public void testVisitNodesByDFS() {
		fail("Not yet implemented");
	}

	@Test
	public void testVisitEdgesByWFS() {
		Options.v().set_whole_program(true);
		Options.v().set_keep_line_number(true);
		// Options.v().setPhaseOption("cg", "verbose:true");
		Options.v().setPhaseOption("cg", "safe-forname:true");
		Options.v().setPhaseOption("cg", "safe-newinstance:true");

		String packageName = "wei.he.stkm";
		String className = "Main";
		// SootClass mainClass = Scene.v().loadClassAndSupport(
		// "testers.CallGraphs");
		SootClass mainClass = Scene.v().loadClassAndSupport(
				packageName + "." + className);
		mainClass.setApplicationClass();
		Scene.v().setMainClass(mainClass);

		// SootClass a = Scene.v().loadClassAndSupport("testers.A");
		SootClass a = Scene.v().loadClassAndSupport("wei.he.stkm.Bike");
		SootClass b = Scene.v().loadClassAndSupport("wei.he.stkm.BikeShop");
		SootClass c = Scene.v().loadClassAndSupport("wei.he.stkm.Fiero");
		SootClass d = Scene.v().loadClassAndSupport("wei.he.stkm.Pulsar");
		SootClass e = Scene.v().loadClassAndSupport("wei.he.stkm.Splendor");
		a.setApplicationClass();
		b.setApplicationClass();
		c.setApplicationClass();
		d.setApplicationClass();
		e.setApplicationClass();

		CHATransformer.v().transform();

		CallGraph cg = Scene.v().getCallGraph();
		List<Edge> edgeIt = CallGraphVisitor.visitEdgesInTopologicalOrder(cg, true);

		for(Edge edge: edgeIt){
			System.out.println("Src: " + edge.getSrc() + ", Tgt: " + edge.getTgt());
		}

		// fail("Not yet implemented");
	}
	
	@Test
	public void testVisitEdgesByWFS2() {
		Options.v().set_whole_program(true);
		Options.v().set_keep_line_number(true);
		// Options.v().setPhaseOption("cg", "verbose:true");
		Options.v().setPhaseOption("cg", "safe-forname:true");
		Options.v().setPhaseOption("cg", "safe-newinstance:true");

		String packageName = "wei.he.stkm";
		String className = "Main";
		// SootClass mainClass = Scene.v().loadClassAndSupport(
		// "testers.CallGraphs");
		SootClass mainClass = Scene.v().loadClassAndSupport(
				packageName + "." + className);
		mainClass.setApplicationClass();
		Scene.v().setMainClass(mainClass);

		// SootClass a = Scene.v().loadClassAndSupport("testers.A");
		SootClass a = Scene.v().loadClassAndSupport("wei.he.stkm.Bike");
		SootClass b = Scene.v().loadClassAndSupport("wei.he.stkm.BikeShop");
		SootClass c = Scene.v().loadClassAndSupport("wei.he.stkm.Fiero");
		SootClass d = Scene.v().loadClassAndSupport("wei.he.stkm.Pulsar");
		SootClass e = Scene.v().loadClassAndSupport("wei.he.stkm.Splendor");
		a.setApplicationClass();
		b.setApplicationClass();
		c.setApplicationClass();
		d.setApplicationClass();
		e.setApplicationClass();

		CHATransformer.v().transform();

		CallGraph cg = Scene.v().getCallGraph();
		List<Edge> edgeIt = CallGraphVisitor.visitEdgesInTopologicalOrder(cg, false);

		for(Edge edge: edgeIt){
			System.out.println("Src: " + edge.getSrc() + ", Tgt: " + edge.getTgt());
		}

		// fail("Not yet implemented");
	}

	@Test
	public void testVisitEdgesByDFS() {
		fail("Not yet implemented");
	}

	@Test
	public void testGetPossibleQuiescentMethods() {
		Options.v().set_whole_program(true);
		Options.v().set_keep_line_number(true);
		// Options.v().setPhaseOption("cg", "verbose:true");
		Options.v().setPhaseOption("cg", "safe-forname:true");
		Options.v().setPhaseOption("cg", "safe-newinstance:true");

		String packageName = "wei.he.stkm";
		String className = "Main";
		// SootClass mainClass = Scene.v().loadClassAndSupport(
		// "testers.CallGraphs");
		SootClass mainClass = Scene.v().loadClassAndSupport(
				packageName + "." + className);
		mainClass.setApplicationClass();
		Scene.v().setMainClass(mainClass);

		// SootClass a = Scene.v().loadClassAndSupport("testers.A");
		SootClass a = Scene.v().loadClassAndSupport("wei.he.stkm.Bike");
		SootClass b = Scene.v().loadClassAndSupport("wei.he.stkm.BikeShop");
		SootClass c = Scene.v().loadClassAndSupport("wei.he.stkm.Fiero");
		SootClass d = Scene.v().loadClassAndSupport("wei.he.stkm.Pulsar");
		SootClass e = Scene.v().loadClassAndSupport("wei.he.stkm.Splendor");
		a.setApplicationClass();
		b.setApplicationClass();
		c.setApplicationClass();
		d.setApplicationClass();
		e.setApplicationClass();

		CHATransformer.v().transform();

		CallGraph cg = Scene.v().getCallGraph();
		List<SootMethod> mtdList = CallGraphVisitor
				.getPossibleQuiescentMethods(cg);
		for (SootMethod mtd : mtdList) {
			System.out.println(mtd);
		}
	}

}
